home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume10 / comobj.lisp / part08 < prev    next >
Encoding:
Text File  |  1987-08-01  |  56.7 KB  |  1,465 lines

  1. Path: uunet!rs
  2. From: rs@uunet.UU.NET (Rich Salz)
  3. Newsgroups: comp.sources.unix
  4. Subject: v10i082:  Common Objects, Common Loops, Common Lisp, Part08/13
  5. Message-ID: <751@uunet.UU.NET>
  6. Date: 3 Aug 87 03:02:26 GMT
  7. Organization: UUNET Communications Services, Arlington, VA
  8. Lines: 1454
  9. Approved: rs@uunet.UU.NET
  10.  
  11. Submitted-by: Roy D'Souza <dsouza%hplabsc@hplabs.HP.COM>
  12. Posting-number: Volume 10, Issue 82
  13. Archive-name: comobj.lisp/Part08
  14.  
  15. #! /bin/sh
  16. # This is a shell archive.  Remove anything before this line, then unpack
  17. # it by saving it into a file and typing "sh file".  To overwrite existing
  18. # files, type "sh file -c".  You can also feed this as standard input via
  19. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  20. # will see the following message at the end:
  21. #        "End of archive 8 (of 13)."
  22. # Contents:  class-prot.l low.l
  23. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  24. if test -f 'class-prot.l' -a "${1}" != "-c" ; then 
  25.   echo shar: Will not clobber existing file \"'class-prot.l'\"
  26. else
  27. echo shar: Extracting \"'class-prot.l'\" \(26632 characters\)
  28. sed "s/^X//" >'class-prot.l' <<'END_OF_FILE'
  29. X;;;-*-Mode:LISP; Package:(PCL Lisp 1000); Base:10; Syntax:Common-lisp -*-
  30. X;;;
  31. X;;; *************************************************************************
  32. X;;; Copyright (c) 1985 Xerox Corporation.  All rights reserved.
  33. X;;;
  34. X;;; Use and copying of this software and preparation of derivative works
  35. X;;; based upon this software are permitted.  Any distribution of this
  36. X;;; software or derivative works must comply with all applicable United
  37. X;;; States export control laws.
  38. X;;; 
  39. X;;; This software is made available AS IS, and Xerox Corporation makes no
  40. X;;; warranty about the software, its performance or its conformity to any
  41. X;;; specification.
  42. X;;; 
  43. X;;; Any person obtaining a copy of this software is requested to send their
  44. X;;; name and post office or electronic mail address to:
  45. X;;;   CommonLoops Coordinator
  46. X;;;   Xerox Artifical Intelligence Systems
  47. X;;;   2400 Hanover St.
  48. X;;;   Palo Alto, CA 94303
  49. X;;; (or send Arpanet mail to CommonLoops-Coordinator.pa@Xerox.arpa)
  50. X;;;
  51. X;;; Suggestions, comments and requests for improvements are also welcome.
  52. X;;; *************************************************************************
  53. X;;;
  54. X
  55. X(in-package 'pcl)
  56. X
  57. X;;;
  58. X;;; ADD-NAMED-CLASS  proto-class name local-supers local-slot-slotds extra
  59. X;;; protocol: class-definition
  60. X;;;
  61. X;;; Creates or updates the definition of a class with a named class.  If
  62. X;;; there is already a class named name, calls class-for-redefinition to
  63. X;;; find out which class to use for the redefinition.  Once it has a class
  64. X;;; object to use it stores the relevant information from the ds-options in
  65. X;;; the class and calls add-class to add the class to the class
  66. X;;; lattice.
  67. X;;; 
  68. X(defmeth add-named-class ((proto-class basic-class) name
  69. X                            local-supers
  70. X                            local-slot-slotds
  71. X                            extra)
  72. X  ;; First find out if there is already a class with this name.
  73. X  ;; If there is, call class-for-redefinition to get the class
  74. X  ;; object to use for the new definition.  If there is no exisiting
  75. X  ;; class we just make a new instance.
  76. X  (let* ((existing (class-named name t))
  77. X     (class (if existing
  78. X            (class-for-redefinition existing proto-class name 
  79. X                        local-supers local-slot-slotds
  80. X                        extra)
  81. X            (make (class-of proto-class)))))
  82. X
  83. X    (setq local-supers
  84. X      (mapcar
  85. X        #'(lambda (ls)
  86. X        (or (class-named ls t)
  87. X            (error "~S was specified as the name of a local-super~%~
  88. X                            for the class named ~S.  But there is no class~%~
  89. X                            class named ~S." ls name ls)))
  90. X        local-supers))
  91. X    
  92. X    (setf (class-name class) name)
  93. X    (setf (class-ds-options class) extra)    ;This is NOT part of the
  94. X                        ;standard protocol.
  95. X   
  96. X    (add-class class local-supers local-slot-slotds extra)
  97. X    
  98. X    (setf (class-named name) class)
  99. X    name))
  100. X
  101. X(defmeth add-class
  102. X     ((class essential-class) new-local-supers new-local-slots extra)
  103. X  (ignore extra)
  104. X  (let ((old-local-supers (class-local-supers class))
  105. X    (old-local-slots (class-local-slots class)))
  106. X    
  107. X    (setf (class-local-supers class) new-local-supers)
  108. X    (setf (class-local-slots class) new-local-slots)
  109. X
  110. X    (if (and old-local-supers            ;*** YUCH!! There is a bug
  111. X         new-local-supers            ;*** when old and new are ()
  112. X         (equal old-local-supers new-local-supers))
  113. X    (if (and old-local-slots
  114. X         new-local-slots
  115. X         (equal old-local-slots new-local-slots))
  116. X        ;; If the supers haven't changed, and the slots haven't changed
  117. X        ;; then not much has changed and we don't have to do anything.
  118. X        ()
  119. X        ;; If only the slots have changed call slots-changed.
  120. X        (slots-changed class old-local-slots extra t))
  121. X    ;; If the supers have changed, first update local-supers and
  122. X    ;; direct-subclasses of all the people involved.  Then call
  123. X    ;; supers-changed.
  124. X    (progn
  125. X      (dolist (nls new-local-supers)
  126. X        (unless (memq nls old-local-supers)
  127. X          (check-super-metaclass-compatibility class nls)
  128. X          (push class (class-direct-subclasses nls))))
  129. X      (dolist (ols old-local-supers)
  130. X        (unless (memq ols new-local-supers)
  131. X          (setf (class-direct-subclasses ols)
  132. X            (delq class (class-direct-subclasses ols)))))
  133. X      (supers-changed class old-local-supers old-local-slots extra t)))))
  134. X
  135. X
  136. X(defmeth supers-changed ((class basic-class)
  137. X             old-local-supers
  138. X             old-local-slots
  139. X             extra
  140. X             top-p)
  141. X  (ignore old-local-slots)
  142. X  (let ((cpl (compute-class-precedence-list class)))
  143. X    (setf (class-class-precedence-list class) cpl)
  144. X    (update-slots--class class cpl)                 ;This is NOT part of
  145. X                                 ;the essential-class
  146. X                                 ;protocol.
  147. X    (dolist (sub-class (class-direct-subclasses class))
  148. X      (supers-changed sub-class
  149. X              (class-local-supers sub-class)
  150. X              (class-local-slots sub-class)
  151. X              extra
  152. X              nil))
  153. X    (when top-p                                          ;This is NOT part of
  154. X      (update-method-inheritance class old-local-supers));the essential-class
  155. X                                 ;protocol.
  156. X    ))
  157. X
  158. X(defmeth slots-changed ((class basic-class)
  159. X            old-local-slots
  160. X            extra
  161. X            top-p)
  162. X  (ignore top-p old-local-slots)
  163. X  ;; When this is called, class should have its local-supers and
  164. X  ;; local-slots slots filled in properly.
  165. X  (update-slots--class class (class-class-precedence-list class))
  166. X  (dolist (sub-class (class-direct-subclasses class))
  167. X    (slots-changed sub-class (class-local-slots sub-class) extra nil)))
  168. X
  169. X(defun update-slots--class (class cpl)
  170. X  (let ((obsolete-class nil))
  171. X    (multiple-value-bind (instance-slots non-instance-slots)
  172. X    (collect-slotds class (class-local-slots class) cpl)
  173. X      ;; If there is a change in the shape of the instances then the
  174. X      ;; old class is now obsolete.  Make a copy of it, then fill
  175. X      ;; ourselves in properly and obsolete it.
  176. X      (when (and (class-has-instances-p class)
  177. X         (not (same-shape-slots-p (class-instance-slots class)
  178. X                      instance-slots)))
  179. X    (setq obsolete-class (copy-class class)))
  180. X      (setf (class-no-of-instance-slots class) (length instance-slots))
  181. X      (setf (class-instance-slots class) instance-slots)
  182. X      (setf (class-non-instance-slots class) non-instance-slots)
  183. X      (when obsolete-class
  184. X    (flush-class-caches class)
  185. X    (make-class-obsolete class (copy-class class))))))
  186. X
  187. X;;;
  188. X;;; CLASS-FOR-REDEFINITION old-class proto-class name ds-options slotds
  189. X;;; protocol: class definition
  190. X;;; 
  191. X;;; When a class is being defined, and a class with that name already exists
  192. X;;; a decision must be made as to what to use for the new class object, and
  193. X;;; whether to update the old class object.  For this, class-for-redefinition
  194. X;;; is called with the old class object, the prototype of the new class, and
  195. X;;; the name ds-options and slotds corresponding to the new definition.
  196. X;;; It should return the class object to use as the new definition.  It is
  197. X;;; OK for this to be old-class if that is appropriate.
  198. X;;; 
  199. X(defmeth class-for-redefinition ((old-class essential-class)
  200. X                 proto-class
  201. X                 name
  202. X                 local-supers
  203. X                 local-slot-slotds
  204. X                 extra)
  205. X  (ignore local-supers local-slot-slotds extra)
  206. X  (cond ((not (compatible-meta-class-change-p old-class proto-class))
  207. X     (error "The class ~A already exists; its class is ~A.~%~
  208. X         The :class argument in the defstruct is ~A.
  209. X         This is an incompatible meta-class change.~%"
  210. X        name
  211. X        (class-name (class-of old-class))
  212. X        (class-name (class-of proto-class))))
  213. X    (t (values old-class (copy-class old-class)))))
  214. X
  215. X(defmeth update-method-inheritance ((class basic-class) old-local-supers)
  216. X  ;; In the absence of method combination, we have to flush all the
  217. X  ;; discriminators which we used to inherit and all the discriminators
  218. X  ;; which we now inherit.
  219. X  (let ((old-mil
  220. X      (compute-method-inheritance-list class old-local-supers))
  221. X    (new-mil
  222. X      (compute-method-inheritance-list class
  223. X                       (class-local-supers class)))
  224. X    (discriminators ())
  225. X    (combined-discriminators ()))
  226. X    (dolist (old-donor old-mil)
  227. X      (when (setq discriminators (class-direct-discriminators old-donor))
  228. X    (dolist (old-discriminator discriminators)      
  229. X      (flush-discriminator-caches old-discriminator)
  230. X      (when (methods-combine-p old-discriminator)
  231. X        (pushnew old-discriminator combined-discriminators)))))
  232. X    (dolist (new-donor new-mil)
  233. X      (when (setq discriminators (class-direct-discriminators new-donor))
  234. X    (unless (memq new-donor old-mil)
  235. X      (dolist (new-discriminator discriminators)
  236. X        (when (methods-combine-p new-discriminator)
  237. X          (pushnew new-discriminator combined-discriminators))
  238. X        (flush-discriminator-caches new-discriminator)))))
  239. X    (when (fboundp 'combine-methods)                 ;***
  240. X      (COMBINE-METHODS CLASS COMBINED-DISCRIMINATORS)))) ;***
  241. X
  242. X
  243. X(defmeth discriminator-changed ((discriminator essential-discriminator)
  244. X                method
  245. X                added-p)
  246. X  (ignore method added-p)
  247. X  (make-discriminating-function discriminator)
  248. X  (flush-discriminator-caches discriminator))
  249. X
  250. X
  251. X(defun make-class-obsolete (class obsolete-class)
  252. X  (setf (class-wrapper-class (class-wrapper obsolete-class)) obsolete-class)
  253. X  (setf (class-wrapper class) nil)
  254. X  (setf (class-local-supers obsolete-class) (list class))
  255. X  (setf (class-class-precedence-list obsolete-class)
  256. X        (cons obsolete-class (class-class-precedence-list class)))
  257. X  (setf (class-name obsolete-class)
  258. X    (symbol-append "obsolete-" (class-name class)))
  259. X  (setf (iwmc-class-class-wrapper obsolete-class)
  260. X        (wrapper-of (class-named 'obsolete-class)))
  261. X  obsolete-class)
  262. X
  263. X(defun copy-class (class) 
  264. X  (let* ((no-of-instance-slots (class-no-of-instance-slots (class-of class)))
  265. X         (new-class (%allocate-instance--class no-of-instance-slots)))
  266. X    (setf (iwmc-class-class-wrapper new-class)
  267. X      (iwmc-class-class-wrapper class))
  268. X    (iterate ((i from 0 below no-of-instance-slots))
  269. X      (let ((index (%convert-slotd-position-to-slot-index i)))
  270. X    (setf (get-static-slot--class new-class index)            
  271. X          (get-static-slot--class class index))))
  272. X    (setf (iwmc-class-dynamic-slots new-class)
  273. X          (copy-list (iwmc-class-dynamic-slots class)))
  274. X    new-class))
  275. X
  276. X(defun wrapper-of (class)
  277. X  (or (class-wrapper class)
  278. X      (setf (class-wrapper class) (make-class-wrapper class))))
  279. X
  280. X(defmeth collect-slotds ((class basic-class) local-slots cpl)
  281. X  (let ((slots ()))
  282. X    (flet ((add-slotd (slotd)
  283. X         (let ((entry
  284. X             (or (assq (slotd-name slotd) slots)
  285. X             (progn (push (list (slotd-name slotd)) slots)
  286. X                (car slots)))))
  287. X           (push slotd (cdr entry)))))
  288. X      (dolist (super (reverse (cdr cpl)))    ;fix this consing later
  289. X    (dolist (super-slotd (class-local-slots super))
  290. X      (add-slotd super-slotd)))
  291. X
  292. X      (dolist (local-slotd local-slots)
  293. X    (add-slotd local-slotd)))
  294. X      
  295. X    ;; Now use compute-effective-slotd to condense all the
  296. X    ;; inherited slotds into the one effective slotd.
  297. X    (dolist (slot slots)
  298. X      (setf (car slot)
  299. X        (compute-effective-slotd class (cdr slot))))
  300. X    ;; Now we need to separate it back out into instance and non-instance
  301. X    ;; slots.
  302. X    (let ((instance ())
  303. X      (non-instance ()))
  304. X      (dolist (slot slots)
  305. X    (setq slot (car slot))
  306. X    (if (eq (slotd-allocation slot) ':instance)
  307. X        (push slot instance)
  308. X        (push slot non-instance)))
  309. X      (values instance non-instance slots))))
  310. X
  311. X(defmethod compute-effective-slotd ((class class) slotds)
  312. X  (ignore class)
  313. X  (let ((slotd  (if (null (cdr slotds))
  314. X            (car slotds)
  315. X            (copy-slotd (car slotds)))))
  316. X    (flet ((merge-values (default type read-only accessor allocation)
  317. X         (macrolet ((merge-value (name value)
  318. X              `(when (eq (,name slotd) *slotd-unsupplied*)
  319. X                 (setf (,name slotd) ,value))))
  320. X           (merge-value slotd-default default)
  321. X           (merge-value slotd-type type)
  322. X           (merge-value slotd-read-only read-only)
  323. X           (merge-value slotd-accessor accessor)
  324. X           (merge-value slotd-allocation allocation))))
  325. X      (dolist (s (cdr slotds))
  326. X    (merge-values (slotd-default s)
  327. X              (slotd-type s)
  328. X              (slotd-read-only s)
  329. X              (slotd-accessor s)
  330. X              (slotd-allocation s)))
  331. X      (merge-values 'nil      ;default value -- for now
  332. X            't        ;type
  333. X            'nil      ;read-only
  334. X            'nil      ;accessor
  335. X          :instance)) ;allocation
  336. X    slotd))
  337. X
  338. X(defmethod compute-class-precedence-list ((root class))
  339. X  #+Lucid (declare (optimize (speed 0) (safety 3)))
  340. X  (let ((*cpl* ())
  341. X    (*root* root)
  342. X    (*must-precede-alist* ()))
  343. X    (declare (special *cpl* *root* *must-precede-alist*))
  344. X    ;; We start by computing two values.
  345. X    ;;   CPL
  346. X    ;;     The depth-first left-to-right up to joins walk of the supers tree.
  347. X    ;;     This is equivalent to breadth-first left-to-right walk of the
  348. X    ;;     tree with all but the last occurence of a class removed from
  349. X    ;;     the resulting list.  This is in fact how the walk is implemented.
  350. X    ;;
  351. X    ;;   MUST-PRECEDE-ALIST
  352. X    ;;     An alist of the must-precede relations. The car of each element
  353. X    ;;     of the must-precede-alist is a class, the cdr is all the classes
  354. X    ;;     which either:
  355. X    ;;       have this class as a local super
  356. X    ;;      or
  357. X    ;;       appear before this class in some other class's local-supers.
  358. X    ;;
  359. X    ;;     Thus, the must-precede-alist reflects the two constraints that:
  360. X    ;;       1. A class must appear in the CPL before its local supers.
  361. X    ;;       2. Order of local supers is preserved in the CPL.
  362. X    ;;
  363. X    (labels
  364. X   ;(flet
  365. X       (
  366. X;    (walk-supers (class &optional precedence)
  367. X;      (let ((elem (assq class must-precede-alist)))
  368. X;        (if elem
  369. X;        (setf (cdr elem) (union (cdr elem) precedence))
  370. X;        (push (cons class precedence) must-precede-alist)))
  371. X;      (let ((rsupers (reverse (cons class (class-local-supers class)))))
  372. X;        (iterate ((sup in rsupers)
  373. X;              (pre on (cdr rsupers))
  374. X;              (temp = nil))
  375. X;          ;; Make sure this element of supers is OK.
  376. X;          ;;  Actually, there is an important design decision hidden in
  377. X;          ;;  here.  Namely, at what time should symbols in a class's
  378. X;          ;;  local-supers be changed to the class objects they are
  379. X;          ;;  forward referencing.
  380. X;          ;;   1. At first make-instance (compute-class-precedence-list)?
  381. X;          ;;   2. When the forward referenced class is first defined?
  382. X;          ;;  This code does #1.
  383. X;          (cond ((classp sup))
  384. X;            ((and (symbolp sup)
  385. X;              (setq temp (class-named sup t)))
  386. X;             ;; This is a forward reference to a class which is
  387. X;             ;; now defined.  Replace the symbol in the local
  388. X;             ;; supers with the actual class object, and set sup.
  389. X;             (nsubst temp sup (class-local-supers class))
  390. X;             (setq sup temp))
  391. X;            ((symbolp sup)
  392. X;             (error "While computing the class-precedence-list for ~
  393. X;                             the class ~S.~%~
  394. X;                             The class ~S (from the local supers of ~S) ~
  395. X;                             is undefined."
  396. X;                (class-name root) sup (class-name class)))
  397. X;            (t
  398. X;             (error "INTERNAL ERROR --~%~
  399. X;                             While computing the class-precedence-list for ~
  400. X;                             the class ~S,~%~
  401. X;                             ~S appeared in the local supers of ~S."
  402. X;                root sup class)))
  403. X;          (walk-supers sup pre))
  404. X;        (unless (memq class cpl) (push class cpl))))
  405. X    (must-move-p (element list &aux move)
  406. X      (dolist (must-precede (cdr (assq element *must-precede-alist*)))
  407. X        (when (setq move (memq must-precede (cdr list)))
  408. X          (return move))))
  409. X    (find-farthest-move (element move)
  410. X      (let ((closure (compute-must-precedes-closure element)))
  411. X        (dolist (must-precede closure)
  412. X          (setq move (or (memq must-precede move) move)))
  413. X        move))
  414. X    (compute-must-precedes-closure (class)
  415. X      (let ((closure ()))
  416. X        (labels ((walk (element path)
  417. X               (when (memq element path)
  418. X             (class-ordering-error
  419. X               *root* element path *must-precede-alist*))
  420. X               (dolist (precede
  421. X                 (cdr (assq element
  422. X                        *must-precede-alist*)))
  423. X             (unless (memq precede closure)
  424. X               (pushnew precede closure)
  425. X               (walk precede (cons element path))))))
  426. X          (walk class nil)
  427. X          closure))))
  428. X      
  429. X      (walk-supers *root*)            ;Do the walk
  430. X      ;; For each class in the cpl, make sure that there are no classes after
  431. X      ;; it which should be before it.  We do this by cdring down the list,
  432. X      ;; making sure that for each element of the list, none of its
  433. X      ;; must-precedes come after it in the list. If we find one, we use the
  434. X      ;; transitive closure of the must-precedes (call find-farthest-move) to
  435. X      ;; see where the class must really be moved. We use a hand-coded loop
  436. X      ;; so that we can splice things in and out of the CPL as we go.
  437. X      (let ((tail *cpl*)
  438. X        (element nil)
  439. X        (move nil))
  440. X    (loop (when (null tail) (return))
  441. X          (setq element (car tail)
  442. X            move (must-move-p element tail))
  443. X          (cond (move
  444. X             (setq move (find-farthest-move element move))
  445. X             (setf (cdr move) (cons element (cdr move)))
  446. X             (setf (car tail) (cadr tail)) ;Interlisp delete is OK
  447. X             (setf (cdr tail) (cddr tail)) ;since it will never be
  448. X                           ;last element of list.
  449. X             )
  450. X            (t
  451. X             (setq tail (cdr tail)))))
  452. X    (copy-list *cpl*)))))
  453. X
  454. X(defun walk-supers (class &optional precedence)
  455. X  (declare (special *cpl* *root* *must-precede-alist*))
  456. X  (let ((elem (assq class *must-precede-alist*)))
  457. X    (if elem
  458. X    (setf (cdr elem) (union (cdr elem) precedence))
  459. X    (push (cons class precedence) *must-precede-alist*)))
  460. X  (let ((rsupers (reverse (cons class (class-local-supers class)))))
  461. X    (iterate ((sup in rsupers)
  462. X          (pre on (cdr rsupers))
  463. X          (temp = nil))
  464. X      ;; Make sure this element of supers is OK.
  465. X      ;;  Actually, there is an important design decision hidden in
  466. X      ;;  here.  Namely, at what time should symbols in a class's
  467. X      ;;  local-supers be changed to the class objects they are
  468. X      ;;  forward referencing.
  469. X      ;;   1. At first make-instance (compute-class-precedence-list)?
  470. X      ;;   2. When the forward referenced class is first defined?
  471. X      ;;  This code does #1.
  472. X      (cond ((classp sup))
  473. X        ((and (symbolp sup)
  474. X          (setq temp (class-named sup t)))
  475. X         ;; This is a forward reference to a class which is
  476. X         ;; now defined.  Replace the symbol in the local
  477. X         ;; supers with the actual class object, and set sup.
  478. X         (nsubst temp sup (class-local-supers class))
  479. X         (setq sup temp))
  480. X        ((symbolp sup)
  481. X         (error "While computing the class-precedence-list for ~
  482. X                             the class ~S.~%~
  483. X                             The class ~S (from the local supers of ~S) ~
  484. X                             is undefined."
  485. X            (class-name *root*) sup (class-name class)))
  486. X        (t
  487. X         (error "INTERNAL ERROR --~%~
  488. X                             While computing the class-precedence-list for ~
  489. X                             the class ~S,~%~
  490. X                             ~S appeared in the local supers of ~S."
  491. X            *root* sup class)))
  492. X      (walk-supers sup pre))
  493. X    (unless (memq class *cpl*) (push class *cpl*))))
  494. X
  495. X(defun class-ordering-error (root element path must-precede-alist)
  496. X  (ignore root)
  497. X  (setq path (cons element (reverse (memq element (reverse path)))))
  498. X  (flet ((pretty (class) (or (class-name class) class)))
  499. X    (let ((explanations ()))
  500. X      (do ((tail path (cdr tail)))
  501. X      ((null (cdr tail)))
  502. X    (let ((after (cadr tail))
  503. X          (before (car tail)))
  504. X      (if (memq after (class-local-supers before))
  505. X          (push (format nil
  506. X                "~% ~A must precede ~A -- ~
  507. X                              ~A is in the local supers of ~A."
  508. X                (pretty before) (pretty after)
  509. X                (pretty after) (pretty before))
  510. X            explanations)
  511. X          (dolist (common-precede
  512. X            (intersection
  513. X              (cdr (assq after must-precede-alist))
  514. X              (cdr (assq before must-precede-alist))))
  515. X        (when (memq after (memq before
  516. X                    (class-local-supers common-precede)))
  517. X          (push (format nil
  518. X                "~% ~A must precede ~A -- ~
  519. X                                  ~A has local supers ~S."
  520. X                (pretty before) (pretty after)
  521. X                (pretty common-precede)
  522. X                (mapcar #'pretty
  523. X                    (class-local-supers common-precede)))
  524. X            explanations))))))
  525. X      (error "While computing the class-precedence-list for the class ~A:~%~
  526. X              There is a circular constraint through the classes:~{ ~A~}.~%~
  527. X              This arises because:~{~A~}"
  528. X         (pretty root)
  529. X         (mapcar #'pretty path)
  530. X         (reverse explanations)))))
  531. X
  532. X(defmeth compute-method-inheritance-list ((class essential-class)
  533. X                      local-supers)
  534. X  (compute-class-precedence-list class))
  535. X
  536. X(defmeth compatible-meta-class-change-p (class proto-new-class)
  537. X  (eq (class-of class) (class-of proto-new-class)))
  538. X
  539. X(defmeth check-super-metaclass-compatibility (class new-super)
  540. X  (unless (eq (class-of class) (class-of new-super))
  541. X    (error "The class ~S was specified as a~%super-class of the class ~S;~%~
  542. X            but the meta-classes ~S and~%~S are incompatible."
  543. X       new-super class (class-of new-super) (class-of class))))
  544. X
  545. X(defun classp (x)
  546. X  (and (iwmc-class-p x) (typep--class x 'essential-class)))
  547. X
  548. X
  549. X
  550. X(defmeth class-standard-constructor ((class basic-class))
  551. X  (dolist (constructor (ds-options-constructors (class-ds-options class)))
  552. X    (when (null (cdr constructor)) (return (car constructor)))))
  553. X
  554. X
  555. X(defmeth flush-class-caches ((class basic-class))
  556. X  (let ((wrapper (class-wrapper class)))
  557. X    (and wrapper (flush-class-wrapper-cache wrapper))
  558. X    (iterate ((subclass in (class-direct-subclasses class)))
  559. X      (flush-class-caches subclass))))
  560. X
  561. X
  562. X  ;;   
  563. X;;;;;; CHANGE-CLASS
  564. X  ;;   
  565. X
  566. X(defun change-class (object new-class)
  567. X  (or (classp new-class)
  568. X      (setq new-class (class-named new-class)))
  569. X  (let ((new-object (make new-class)))
  570. X    ;; Call change-class-internal so that a user-defined method
  571. X    ;; (or the default method) can copy the information from the
  572. X    ;; old instance to the dummy instance of the new class.
  573. X    (change-class-internal object new-object)
  574. X    ;; Now that the dummy new-object has the right information,
  575. X    ;; move all that stuff into the old-instance.
  576. X    (setf (iwmc-class-class-wrapper object)
  577. X      (wrapper-of new-class))
  578. X    (setf (iwmc-class-static-slots object)
  579. X      (iwmc-class-static-slots new-object))
  580. X    (setf (iwmc-class-dynamic-slots object)
  581. X      (iwmc-class-dynamic-slots new-object))
  582. X    object))
  583. X
  584. X(defmeth change-class-internal ((old object) (new object))
  585. X  (let ((all-slots (all-slots old)))
  586. X    (iterate ((name in all-slots by cddr)
  587. X              (value in (cdr all-slots) by cddr))
  588. X      (put-slot-always new name value))))
  589. X
  590. X  ;;   
  591. X;;;;;; WITH-SLOTS
  592. X  ;;
  593. X
  594. X(define-method-body-macro with-slots (instance-forms-and-options
  595. X                       &body body
  596. X                       &environment env)
  597. X  :global (expand-with-slots nil nil instance-forms-and-options env body)
  598. X  :method (expand-with-slots (macroexpand-time-generic-function
  599. X                   macroexpand-time-environment)
  600. X                 (macroexpand-time-method
  601. X                   macroexpand-time-environment)
  602. X                 instance-forms-and-options
  603. X                 env
  604. X                 body))
  605. X
  606. X(defun expand-with-slots (proto-discriminator proto-method first-arg env body)
  607. X  (ignore proto-discriminator)
  608. X  (setq first-arg (iterate ((arg in first-arg))
  609. X            (collect (if (listp arg) arg (list arg)))))
  610. X  (let ((entries (expand-with-make-entries proto-method first-arg))
  611. X    (gensyms ()))
  612. X    (dolist (arg first-arg)
  613. X      (push (list (if (listp arg) (car arg) arg)
  614. X          (gensym))
  615. X        gensyms))
  616. X    `(let ,(mapcar #'reverse gensyms)
  617. X       ,(walk-form (cons 'progn body)
  618. X      :environment env
  619. X      :walk-function
  620. X      #'(lambda (form context &aux temp)
  621. X          (cond ((and (symbolp form)
  622. X              (eq context ':eval)
  623. X              (null (variable-lexical-p form))
  624. X              (null (variable-special-p form))
  625. X              (setq temp (assq form entries)))
  626. X             (if (car (cddddr temp))    ;use slot-value?
  627. X             (let ((get-slot 
  628. X                 `(get-slot ,(cadr (assq (cadr temp) gensyms))
  629. X                        ',(slotd-name (cadddr temp)))))
  630. X               (optimize-get-slot (caddr temp)
  631. X                          get-slot))
  632. X             `(,(slotd-accessor (cadddr temp))
  633. X               ,(cadr (assq (cadr temp) gensyms)))))
  634. X            ((and (listp form)
  635. X              (or (eq (car form) 'setq)
  636. X                  (eq (car form) 'setf)))
  637. X             (cond ((cdddr form)
  638. X                (cons 'progn
  639. X                  (iterate ((pair on (cdr form) by cddr))
  640. X                    (collect (list (car form)
  641. X                           (car pair)
  642. X                           (cadr pair))))))
  643. X               ((setq temp (assq (cadr form) entries))
  644. X                (if (car (cddddr temp))
  645. X                (let ((get-slot 
  646. X                    `(setf-of-get-slot
  647. X                       ,(cadr (assq (cadr temp) gensyms))
  648. X                       ',(slotd-name (cadddr temp))
  649. X                       ,(caddr form))))
  650. X                  (optimize-setf-of-get-slot (caddr temp)
  651. X                                 get-slot))
  652. X                `(setf (,(slotd-accessor (cadddr temp))
  653. X                    ,(cadr (assq (cadr temp) gensyms)))
  654. X                       ,(caddr form))))
  655. X               (t form)))
  656. X            (t form)))))))
  657. X
  658. X;;; Returns an alist of the form:
  659. X;;; 
  660. X;;;   (<prefix+slot-name> <instance-form> <class> <slotd> <use-slot-value-p>)
  661. X;;;
  662. X(defmeth expand-with-make-entries (method first-arg)
  663. X  (let* ((entries ())
  664. X         (method-arguments
  665. X       (when (method-p method)
  666. X         (iterate ((arg in (method-arglist method))
  667. X               (spec in (method-type-specifiers method)))
  668. X           (when (classp spec) (collect (cons arg spec)))))))
  669. X    (iterate ((instance-and-keys in first-arg))
  670. X      (keyword-bind ((use-slot-value nil)
  671. X             (class nil class-specified-p)
  672. X             (prefix nil prefix-specified-p))
  673. X            (cdr instance-and-keys)
  674. X    (let ((instance (car instance-and-keys)))
  675. X      (setq class
  676. X        (or (and class-specified-p
  677. X             (or (class-named class t)
  678. X                 (error "In WITH-SLOTS the class specified for ~
  679. X                                     ~S, ~S ~%~
  680. X                                     is not the name of a defined class."
  681. X                    instance class)))
  682. X            (cdr (assq instance method-arguments))
  683. X            (error "The class of (the value of) ~S was not given in ~
  684. X                           in the call to with-slots and could not be ~
  685. X                           inferred automatically."
  686. X              instance)))
  687. X      (iterate ((slotd in (class-slots class)))
  688. X        (push (list (if (null prefix-specified-p)
  689. X                (slotd-name slotd)
  690. X                (intern (string-append prefix
  691. X                           (slotd-name slotd))
  692. X                    (symbol-package
  693. X                      (if (symbolp prefix)
  694. X                      prefix
  695. X                      (slotd-name slotd)))))
  696. X            instance
  697. X            class
  698. X            slotd
  699. X            use-slot-value)
  700. X          entries)))))
  701. X    entries))
  702. X
  703. X
  704. X(defun named-object-print-function (instance stream depth
  705. X                         &optional (extra nil extra-p))
  706. X  (ignore depth)
  707. X  (printing-random-thing (instance stream)
  708. X    ;; I know I don't have to do this this way.  I know I
  709. X    ;; could use ~[~;~], but how many Common Lisps do you
  710. X    ;; think have that completely debugged?
  711. X    (if extra-p                    
  712. X    (format stream "~A ~S ~:S"
  713. X        (capitalize-words (class-name (class-of instance)))
  714. X        (get-slot instance 'name)
  715. X        extra)
  716. X    (format stream "~A ~S"
  717. X        (capitalize-words (class-name (class-of instance)))
  718. X        (get-slot instance 'name)))))
  719. X
  720. END_OF_FILE
  721. if test 26632 -ne `wc -c <'class-prot.l'`; then
  722.     echo shar: \"'class-prot.l'\" unpacked with wrong size!
  723. fi
  724. # end of 'class-prot.l'
  725. fi
  726. if test -f 'low.l' -a "${1}" != "-c" ; then 
  727.   echo shar: Will not clobber existing file \"'low.l'\"
  728. else
  729. echo shar: Extracting \"'low.l'\" \(27849 characters\)
  730. sed "s/^X//" >'low.l' <<'END_OF_FILE'
  731. X;;;-*-Mode:LISP; Package:(PCL (LISP WALKER) 1000); Base:10; Syntax:Common-lisp -*-
  732. X;;;
  733. X;;; *************************************************************************
  734. X;;; Copyright (c) 1985 Xerox Corporation.  All rights reserved.
  735. X;;;
  736. X;;; Use and copying of this software and preparation of derivative works
  737. X;;; based upon this software are permitted.  Any distribution of this
  738. X;;; software or derivative works must comply with all applicable United
  739. X;;; States export control laws.
  740. X;;; 
  741. X;;; This software is made available AS IS, and Xerox Corporation makes no
  742. X;;; warranty about the software, its performance or its conformity to any
  743. X;;; specification.
  744. X;;; 
  745. X;;; Any person obtaining a copy of this software is requested to send their
  746. X;;; name and post office or electronic mail address to:
  747. X;;;   CommonLoops Coordinator
  748. X;;;   Xerox Artifical Intelligence Systems
  749. X;;;   2400 Hanover St.
  750. X;;;   Palo Alto, CA 94303
  751. X;;; (or send Arpanet mail to CommonLoops-Coordinator.pa@Xerox.arpa)
  752. X;;;
  753. X;;; Suggestions, comments and requests for improvements are also welcome.
  754. X;;; *************************************************************************
  755. X;;;
  756. X;;; This file contains portable versions of low-level functions and macros
  757. X;;; which are ripe for implementation specific customization.  None of the
  758. X;;; code in this file *has* to be customized for a particular Common Lisp
  759. X;;; implementation. Moreover, in some implementations it may not make any
  760. X;;; sense to customize some of this code.
  761. X;;;
  762. X;;; But, experience suggests that MOST Common Lisp implementors will want
  763. X;;; to customize some of the code in this file to make PCL run better in
  764. X;;; their implementation.  The code in this file has been separated and
  765. X;;; heavily commented to make that easier.
  766. X;;;
  767. X;;; Implementation-specific version of this file already exist for:
  768. X;;; 
  769. X;;;    Symbolics 3600 family       3600-low.lisp
  770. X;;;    Lucid Lisp                  lucid-low.lisp
  771. X;;;    Xerox 1100 family           1100-low.lisp
  772. X;;;    Ti Explorer                 ti-low.lisp
  773. X;;;    Vaxlisp                     vaxl-low.lisp
  774. X;;;    Spice Lisp                  spice-low.lisp
  775. X;;;    Kyoto Common Lisp           kcl-low.lisp
  776. X;;;    ExCL (Franz)                excl-low.lisp
  777. X;;;    H.P. Common Lisp            hp-low.lisp
  778. X;;;    
  779. X;;;
  780. X;;; These implementation-specific files are loaded after this file.  Because
  781. X;;; none of the macros defined by this file are used in functions defined by
  782. X;;; this file the implementation-specific files can just contain the parts of
  783. X;;; this file they want to change.  They don't have to copy this whole file
  784. X;;; and then change the parts they want.
  785. X;;;
  786. X;;; If you make changes or improvements to these files, or if you need some
  787. X;;; low-level part of PCL re-modularized to make it more portable to your
  788. X;;; system please send mail to CommonLoops.pa@Xerox.com.
  789. X;;;
  790. X;;; Thanks.
  791. X;;; 
  792. X
  793. X(in-package 'pcl)
  794. X
  795. X  ;;   
  796. X;;;;;; without-interrupts
  797. X  ;;   
  798. X;;; OK, Common Lisp doesn't have this and for good reason.  But For all of
  799. X;;; the Common Lisp's that PCL runs on today, there is a meaningful way to
  800. X;;; implement this.  WHAT I MEAN IS:
  801. X;;;
  802. X;;; I want the body to be evaluated in such a way that no other code that is
  803. X;;; running PCL can be run during that evaluation.  I agree that the body
  804. X;;; won't take *long* to evaluate.  That is to say that I will only use
  805. X;;; without interrupts around small computations.
  806. X;;;
  807. X;;; OK?
  808. X;;;
  809. X(defmacro without-interrupts (&body body)
  810. X  `(progn ,.body))
  811. X
  812. X  ;;   
  813. X;;;;;; Load Time Eval
  814. X  ;;
  815. X;;;
  816. X;;; #, is woefully inadequate.  You can't use it inside of a macro and have
  817. X;;; the expansion of part of the macro be evaluated at load-time.
  818. X;;;
  819. X;;; load-time-eval is used to provide an interface to implementation
  820. X;;; dependent implementation of load time evaluation.
  821. X;;;
  822. X;;; A compiled call to load-time-eval:
  823. X;;;   should evaluated the form at load time,
  824. X;;;   but if it is being compiled-to-core evaluate it at compile time
  825. X;;; Interpreted calls to load-time-eval:
  826. X;;;   should just evaluate form at run-time.
  827. X;;; 
  828. X;;; The portable implementation just evaluates it every time, and PCL knows
  829. X;;; this.  PCL is careful to only use load-time-eval in places where (except
  830. X;;; for performance penalty) it is OK to evaluate the form every time.
  831. X;;; 
  832. X(defmacro load-time-eval (form)
  833. X  `(progn ,form))
  834. X
  835. X  ;;   
  836. X;;;;;; Memory Blocks (array-like blocks of memory)
  837. X  ;;
  838. X;;; The portable implementation of memory-blocks is as arrays.
  839. X;;;
  840. X;;; The area argument to make-memory-block is based on the area feature of
  841. X;;; LispM's.  As it is used in PCL that argument will always be an unquoted
  842. X;;; symbol.  So a call to make-memory-block will look like:
  843. X;;;     (make-memory-block 100 class-wrapper-area)
  844. X;;; This allows any particular implementation of make-memory-block to look at
  845. X;;; the symbol at compile time (macroexpand time) and know where the memory-
  846. X;;; block should be consed.  Currently the only values ever used as the area
  847. X;;; argument are:
  848. X;;; 
  849. X;;;    CLASS-WRAPPER-AREA        used when making a class-wrapper
  850. X;;;
  851. X;;; NOTE:
  852. X;;;     It is perfectly legitimate for an implementation of make-memory-block
  853. X;;;     to ignore the area argument.  It only exists to try to improve paging
  854. X;;;     performance in systems which do allow control over where memory is
  855. X;;;     allocated.
  856. X;;; 
  857. X(defmacro make-memory-block (size &optional area)
  858. X  (ignore area)
  859. X  `(make-array ,size :initial-element nil))
  860. X
  861. X(defmacro memory-block-size (block)
  862. X  `(array-dimension ,block 0))
  863. X
  864. X(defmacro memory-block-ref (block offset)
  865. X  `(svref ,block ,offset))
  866. X
  867. X(eval-when (compile load eval)
  868. X
  869. X(defun make-memory-block-mask (size &optional (words-per-entry 2))
  870. X  (logxor (1- (expt 2 (floor (log size 2))))
  871. X      (1- (expt 2 (ceiling (log words-per-entry 2))))))
  872. X
  873. X)
  874. X
  875. X;;;
  876. X;;; clear-memory-block sets all the slots of a memory block to nil starting
  877. X;;; at start.  This really shouldn't be a macro, it should be a function.
  878. X;;; It has to be a macro because otherwise its call to memory-block-ref will
  879. X;;; get compiled before people get a chance to change memory-block-ref.
  880. X;;; This argues one of:
  881. X;;;  - this should be a function in another file.  No, it belongs here.
  882. X;;;  - Common Lisp should have defsubst.  Probably
  883. X;;;  - Implementors should take (proclaim '(inline xxx)) more seriously.
  884. X;;;  
  885. X(defmacro clear-memory-block (block start &optional times)
  886. X  (once-only (block)
  887. X    `(do ((end ,(if times `(+ ,start ,times) `(length ,block)))
  888. X      (index ,start (+ index 1)))
  889. X     ((= index end))
  890. X       (setf (memory-block-ref ,block index) nil))))
  891. X
  892. X  ;;   
  893. X;;;;;; CLASS-OF
  894. X  ;;
  895. X;;;
  896. X;;; *class-of* is the lisp code for the definition of class-of.
  897. X;;;
  898. X;;; This version uses type-of to determine the class of an object.  Because
  899. X;;; of the underspecification of type-of, this does not always produce the
  900. X;;; "most specific class of which x is an instance".  But it is the best I
  901. X;;; can do portably.
  902. X;;;
  903. X;;; Specific ports of PCL should feel free to redefine *class-of* to provide
  904. X;;; a more accurate definition.  At some point in any definition of class-of
  905. X;;; there should be a test to determine if the argument is a %instance, and
  906. X;;; if so the %instance-class-of macro should be used to determine the class
  907. X;;; of the instance.
  908. X;;;
  909. X;;; Whenever a new meta-class is defined, the portable code will take care of
  910. X;;; modifying the definition of %instance-class-of and recompiling class-of.
  911. X;;;
  912. X(defvar *class-of*
  913. X    '(lambda (x) 
  914. X       (or (and (%instancep x)
  915. X            (%instance-class-of x))
  916. X          ;(%funcallable-instance-p x)
  917. X           (class-named (type-of x) t)
  918. X           (error "Can't determine class of ~S" x))))
  919. X
  920. X(defvar *meta-classes* ())
  921. X
  922. X(defmacro %instance-class-of (arg)
  923. X  `(cond ,@(iterate ((mc in *meta-classes*))
  924. X         (collect
  925. X           `((eq (%instance-meta-class ,arg)
  926. X             ;; %^&$%& KCL has to have this stupid call to
  927. X             ;; load-time-eval here because their compiler
  928. X             ;; always creates a file and compiles that file.
  929. X             #-KCL',(class-named (car mc))
  930. X             #+KCL (load-time-eval (class-named ',(car mc))))
  931. X         (funcall (function ,(cdr mc)) ,arg))))
  932. X     (t
  933. X      (error
  934. X        "Internal error in %INSTANCE-CLASS-OF.  The argument to~%~
  935. X             %instance-class-of is a %instance, but its meta-class is~%~
  936. X             not one of the meta-classes defined with define-meta-class."
  937. X        (%instance-meta-class ,arg)))))
  938. X
  939. X(defmacro define-meta-class (name class-of-function &rest options)
  940. X  (check-type name symbol "a symbol which is the name of a meta-class")
  941. X  (check-type class-of-function function "a function")  
  942. X  `(load-define-meta-class ',name ',class-of-function))
  943. X
  944. X(defun load-define-meta-class (name class-of-function)
  945. X  (or (eq name 'class)
  946. X      (class-named name t)
  947. X      (error "In define-meta-class, there is no class named ~S.~%~
  948. X              The class ~S must be defined before evaluating this~%~
  949. X              define-meta-class form."))
  950. X  (let ((existing (assq name *meta-classes*)))
  951. X    (if existing
  952. X    (setf (cdr existing) class-of-function)
  953. X    (setq *meta-classes* (nconc *meta-classes*
  954. X                    (list (cons name class-of-function)))))
  955. X    (recompile-class-of)))
  956. X
  957. X(defun recompile-class-of ()
  958. X    ;; Change the definition of class-of so that the next time it is
  959. X    ;; called it will recompile itself.
  960. X    ;; NOTE:  This does not have to be written this way.  If we impose
  961. X    ;;        the constraint that any define-meta-class must be loaded
  962. X    ;;        in the same environment as it was compiled then there is
  963. X    ;;        no need for a compiler at run or load time.
  964. X    ;;        By same environment I mean with the same define-meta-class
  965. X    ;;        forms already in force, and this certainly seems like a
  966. X    ;;        reasonable constraint to me.
  967. X    (setf (symbol-function 'class-of)
  968. X      #'(lambda (x)
  969. X          (declare (notinline class-of))
  970. X          ;; Now recompile class-of so that the new definition
  971. X          ;; of %instance-class-of will take effect.
  972. X          (compile 'class-of *class-of*)
  973. X          (class-of x))))
  974. X
  975. X  ;;
  976. X;;;;;; TYPEP and TYPE-OF support.
  977. X  ;;
  978. X;;; Portable CommonLoops makes no changes to typep or type-of.  In order for
  979. X;;; those functions to work with CommonLoops objects each implementation will
  980. X;;; have to fix its typep and type-of.  It shouldn't be hard though, and
  981. X;;; these macros should help.
  982. X
  983. X(defmacro %instance-typep (x type)
  984. X  `(not (null (memq (class-named ,type ())
  985. X                    (class-class-precedence-list (class-of ,x))))))
  986. X
  987. X(defmacro %instance-type-of (x)
  988. X  `(class-name (class-of ,x)))
  989. X
  990. X  ;;   
  991. X;;;;;; The primitive instances.
  992. X  ;;
  993. X;;;
  994. X;;; Conceptually, a %instance is an array-like datatype whose first element
  995. X;;; points to the meta-class of the %instance and whose remaining elements
  996. X;;; are used by the meta-class for whatever purpose it wants.
  997. X;;;
  998. X;;; What would like to do is use defstruct to define a new type with a
  999. X;;; variable number of slots.  Unfortunately, Common Lisp itself does not
  1000. X;;; let us do that.  So we have to define a new type %instance, and have
  1001. X;;; it point to an array which is the extra slots.
  1002. X;;;
  1003. X;;; Most any port of PCL should re-implement this datatype.  Implementing it
  1004. X;;; as a variable length type so that %instance are only one vector in memory
  1005. X;;; (the "extra slots" are in-line with the meta-class) will have significant
  1006. X;;; impact on the speed of many CommonLoops programs.  As an example of how
  1007. X;;; to do this re-implementation of %instance, please see the file 3600-low.
  1008. X;;; 
  1009. X
  1010. X(defstruct (%instance (:print-function print-instance)
  1011. X              (:constructor %make-instance-1 (meta-class storage))
  1012. X              (:predicate %instancep))
  1013. X  meta-class
  1014. X  storage)
  1015. X
  1016. X(defmacro %make-instance (meta-class size)
  1017. X  `(%make-instance-1 ,meta-class (make-array ,size)))
  1018. X
  1019. X(defmacro %instance-ref (instance index)
  1020. X  `(aref (%instance-storage ,instance) ,index))
  1021. X
  1022. X(defun print-instance (instance stream depth) ;This is a temporary definition
  1023. X  (ignore depth)                  ;used mostly for debugging the
  1024. X  (printing-random-thing (instance stream)    ;bootstrapping code.
  1025. X    (format stream "instance ??")))
  1026. X
  1027. X  ;;
  1028. X;;;;;;  Very Low-Level representation of instances with meta-class class.
  1029. X  ;;
  1030. X;;; As shown below, an instance with meta-class class (iwmc-class) is a three
  1031. X;;; *slot* structure.
  1032. X;;;   
  1033. X;;; 
  1034. X;;;                                             /------["Class"]
  1035. X;;;                  /-------["Class Wrapper"  /  <slot-and-method-cache>]
  1036. X;;;                 /
  1037. X;;;  Instance--> [ / , \  ,  \ ]
  1038. X;;;                     \     \
  1039. X;;;                      \     \---[Instance Slot Storage Block]
  1040. X;;;                       \
  1041. X;;;                        \-------[Dynamic Slot plist]
  1042. X;;;
  1043. X;;; Instances with meta-class class point to their class indirectly through
  1044. X;;; the class's class wrapper (each class has one class wrapper, not each
  1045. X;;; instance).  This is done so that all the extant instances of a class can
  1046. X;;; have the class they point to changed quickly.  See change-class.
  1047. X;;;
  1048. X;;; Static-slots are a 1-d-array-like structure.
  1049. X;;; The default PCL implementation is as a memory block as described above.
  1050. X;;; Particular ports are free to change this to a lower-level block of memory
  1051. X;;; type structure. Once again, the accessor for static-slots storage doesn't
  1052. X;;; need to do bounds checking, and static-slots structures don't need to be
  1053. X;;; able to change size.  This is because new slots are added using the
  1054. X;;; dynamic slot mechanism, and if the class changes or the class of the
  1055. X;;; instance changes a new static-slot structure is allocated (if needed).
  1056. X;;
  1057. X;;; Dynamic-slots are a plist-like structure.
  1058. X;;; The default PCL implementation is as a plist.
  1059. X;;;
  1060. X;;; *** Put a real discussion here of where things should be consed.
  1061. X;;;  - if all the class wrappers in the world are on the same page that
  1062. X;;;    would be good because during method lookup we only use the wrappers
  1063. X;;;    not the classes and once a slot is cached, we only use the wrappers
  1064. X;;;    too.  So a page of just wrappers would stay around all the time and
  1065. X;;;    you would never have to page in the classes at least in "tight" loops.
  1066. X;;;
  1067. X
  1068. X(defmacro iwmc-class-p (x)
  1069. X  `(and (%instancep ,x)
  1070. X    (eq (%instance-meta-class ,x)
  1071. X        (load-time-eval (class-named 'class)))))
  1072. X
  1073. X;(defmacro %allocate-iwmc-class ()
  1074. X;  `(%make-instance (load-time-eval (class-named 'class)) 3))
  1075. X
  1076. X(defmacro iwmc-class-class-wrapper (iwmc-class)
  1077. X  `(%instance-ref ,iwmc-class 0))
  1078. X
  1079. X(defmacro iwmc-class-static-slots (iwmc-class)
  1080. X  `(%instance-ref ,iwmc-class 1))
  1081. X
  1082. X(defmacro iwmc-class-dynamic-slots (iwmc-class)
  1083. X  `(%instance-ref ,iwmc-class 2))
  1084. X
  1085. X
  1086. X(defmacro %allocate-instance--class (no-of-slots &optional class-class)
  1087. X  `(let ((iwmc-class
  1088. X       (%make-instance ,(or class-class
  1089. X                '(load-time-eval (class-named 'class)))
  1090. X               3)))
  1091. X     (%allocate-instance--class-1 ,no-of-slots iwmc-class)
  1092. X     iwmc-class))
  1093. X
  1094. X(defmacro %allocate-instance--class-1 (no-of-slots instance)
  1095. X  (once-only (instance)
  1096. X    `(progn 
  1097. X       (setf (iwmc-class-static-slots ,instance)
  1098. X         (%allocate-static-slot-storage--class ,no-of-slots))
  1099. X       (setf (iwmc-class-dynamic-slots ,instance)
  1100. X         (%allocate-dynamic-slot-storage--class)))))
  1101. X
  1102. X
  1103. X(defmacro %allocate-class-class (no-of-slots)    ;This is used to allocate the
  1104. X  `(let ((i (%make-instance nil 3)))        ;class class.  It bootstraps
  1105. X     (setf (%instance-meta-class i) i)        ;the call to class-named in
  1106. X     (setf (class-named 'class) i)        ;%allocate-instance--class.
  1107. X     (%allocate-instance--class-1 ,no-of-slots i)
  1108. X     i))
  1109. X
  1110. X(defmacro %convert-slotd-position-to-slot-index (slotd-position)
  1111. X  slotd-position)
  1112. X
  1113. X
  1114. X(defmacro %allocate-static-slot-storage--class (no-of-slots)
  1115. X  `(make-memory-block ,no-of-slots))
  1116. X
  1117. X(defmacro %static-slot-storage-get-slot--class (static-slot-storage
  1118. X                        slot-index)
  1119. X  `(memory-block-ref ,static-slot-storage ,slot-index))
  1120. X
  1121. X(defmacro %allocate-dynamic-slot-storage--class ()
  1122. X  ())
  1123. X
  1124. X(defmacro %dynamic-slot-storage-get-slot--class (dynamic-slot-storage
  1125. X                         name
  1126. X                         default)
  1127. X  `(getf ,dynamic-slot-storage ,name ,default))
  1128. X
  1129. X(defmacro %dynamic-slot-storage-remove-slot--class (dynamic-slot-storage
  1130. X                            name)
  1131. X  `(remf ,dynamic-slot-storage ,name))
  1132. X
  1133. X
  1134. X
  1135. X(defmacro class-of--class (iwmc-class)
  1136. X  `(class-wrapper-class (iwmc-class-class-wrapper ,iwmc-class)))
  1137. X
  1138. X(define-meta-class class (lambda (x) (class-of--class x)))
  1139. X
  1140. X
  1141. X  ;;   
  1142. X;;;;;; Class Wrappers  (the Watercourse Way algorithm)
  1143. X  ;;
  1144. X;;; Well, we had this really cool scheme for keeping multiple different
  1145. X;;; caches tables in the same block of memory.  Unfortunately, we only
  1146. X;;; cache one thing in class wrappers these days, and soon class wrappers
  1147. X;;; will go away entirely so its kind of lost generality.  I am leaving
  1148. X;;; the old comment here cause the hack is worth remembering.
  1149. X;;;
  1150. X;;; * Old Comment
  1151. X;;; * The key point are:
  1152. X;;; *
  1153. X;;; *  - No value in the cache can be a key for anything else stored
  1154. X;;; *    in the cache.
  1155. X;;; *
  1156. X;;; *  - When we invalidate a wrapper cache, we flush it so that when
  1157. X;;; *    it is next touched it will get a miss.
  1158. X;;; *
  1159. X;;; * A class wrapper is a block of memory whose first two slots have a
  1160. X;;; * deadicated (I just can't help myself) purpose and whose remaining
  1161. X;;; * slots are the shared cache table.  A class wrapper looks like:
  1162. X;;; *
  1163. X;;; *  slot 0:   <pointer to class>
  1164. X;;; *  slot 1:   T if wrapper is valid, NIL otherwise.
  1165. X;;; *   .
  1166. X;;; *   .          shared cache
  1167. X;;; *   .
  1168. X;;;
  1169. X
  1170. X(eval-when (compile load eval)
  1171. X
  1172. X(defconstant class-wrapper-cache-size 32
  1173. X  "The size of class-wrapper caches.")
  1174. X
  1175. X(defconstant class-wrapper-leader 2
  1176. X  "The number of slots at the beginning of a class wrapper which have a
  1177. X   special purpose.  These are the slots that are not part of the cache.")
  1178. X
  1179. X; due to a compiler bug, the extra "2" default argument has been added
  1180. X; to the following function invocation, for HP Lisp. rds 3/6/87
  1181. X(defconstant class-wrapper-cache-mask 
  1182. X         (make-memory-block-mask class-wrapper-cache-size 2))
  1183. X
  1184. X)
  1185. X
  1186. X(defmacro make-class-wrapper (class)
  1187. X  `(let ((wrapper (make-memory-block ,(+ class-wrapper-cache-size
  1188. X                     class-wrapper-leader)
  1189. X                     class-wrapper-area)))
  1190. X     (setf (class-wrapper-class wrapper) ,class)
  1191. X     (setf (class-wrapper-valid-p wrapper) t)
  1192. X     wrapper))
  1193. X
  1194. X(defmacro class-wrapper-class (class-wrapper)
  1195. X  `(memory-block-ref ,class-wrapper 0))
  1196. X
  1197. X(defmacro class-wrapper-valid-p (class-wrapper)
  1198. X  `(memory-block-ref ,class-wrapper 1))
  1199. X
  1200. X(defmacro class-wrapper-cached-key (class-wrapper offset)
  1201. X  `(memory-block-ref ,class-wrapper ,offset))
  1202. X
  1203. X(defmacro class-wrapper-cached-val (class-wrapper offset)
  1204. X  `(memory-block-ref ,class-wrapper (+ ,offset 1)))
  1205. X
  1206. X(defmacro class-wrapper-get-slot-offset (class-wrapper slot-name)
  1207. X  (ignore class-wrapper)
  1208. X  `(+ class-wrapper-leader
  1209. X      0
  1210. X      (symbol-cache-no ,slot-name ,class-wrapper-cache-mask)))
  1211. X
  1212. X
  1213. X(defmacro flush-class-wrapper-cache (class-wrapper)
  1214. X  `(clear-memory-block ,class-wrapper
  1215. X               ,class-wrapper-leader
  1216. X               ,class-wrapper-cache-size))
  1217. X
  1218. X(defmacro class-wrapper-cache-cache-entry (wrapper offset key val)
  1219. X  (once-only (wrapper offset key val)
  1220. X    `(without-interrupts
  1221. X       (setf (class-wrapper-cached-key ,wrapper ,offset) ,key)     ;store key
  1222. X       (setf (class-wrapper-cached-val ,wrapper ,offset) ,val))));store value
  1223. X
  1224. X(defmacro class-wrapper-cache-cached-entry (wrapper offset key)
  1225. X  (once-only (wrapper offset)
  1226. X    `(and (eq (class-wrapper-cached-key ,wrapper ,offset) ,key)
  1227. X      (class-wrapper-cached-val ,wrapper ,offset))))
  1228. X
  1229. X(defmacro invalidate-class-wrapper (wrapper)
  1230. X  (once-only (wrapper)
  1231. X    `(progn (flush-class-wrapper-cache ,wrapper)
  1232. X        (setf (class-wrapper-valid-p ,wrapper) nil))))
  1233. X
  1234. X(defmacro validate-class-wrapper (iwmc-class)              ;HAS to be a macro!
  1235. X  `(let ((wrapper (iwmc-class-class-wrapper ,iwmc-class)));So that xxx-low
  1236. X     (if (class-wrapper-valid-p wrapper)              ;can redefine the
  1237. X     wrapper                          ;macros we use.
  1238. X     (progn (setf (iwmc-class-class-wrapper ,iwmc-class)
  1239. X              (class-wrapper (class-wrapper-class wrapper)))
  1240. X        (setf (class-wrapper-valid-p wrapper) t)))))
  1241. X
  1242. X  ;;   
  1243. X;;;;;; Generating CACHE numbers
  1244. X  ;;
  1245. X;;; These macros should produce a CACHE number for their first argument
  1246. X;;; masked to fit in their second argument.  A useful cache number is just
  1247. X;;; the symbol or object's memory address.  The memory address can either
  1248. X;;; be masked to fit the mask or folded down with xor to fit in the mask.
  1249. X;;; See some of the other low files for examples of how to implement these
  1250. X;;; macros. Except for their illustrative value, the portable versions of
  1251. X;;; these macros are nearly worthless.  Any port of CommonLoops really
  1252. X;;; should redefine these to be faster and produce more useful numbers.
  1253. X
  1254. X(defvar *warned-about-symbol-cache-no* nil)
  1255. X(defvar *warned-about-object-cache-no* nil)
  1256. X
  1257. X(defmacro symbol-cache-no (symbol mask)
  1258. X  (unless *warned-about-symbol-cache-no*
  1259. X    (setq *warned-about-symbol-cache-no* t)
  1260. X    (warn
  1261. X      "Compiling PCL without having defined an implementation-specific~%~
  1262. X       version of SYMBOL-CACHE-NO.  This is likely to have a significant~%~
  1263. X       effect on slot-access performance.~%~
  1264. X       See the definition of symbol-cache-no in the file low to get an~%~
  1265. X       idea of how to implement symbol-cache-no."))
  1266. X  `(logand (sxhash ,symbol) ,mask))
  1267. X
  1268. X(defmacro object-cache-no (object mask)
  1269. X  (ignore object)
  1270. X  (unless *warned-about-object-cache-no*
  1271. X    (setq *warned-about-object-cache-no* t)
  1272. X    (warn
  1273. X      "Compiling PCL without having defined an implementation-specific~%~
  1274. X       version of OBJECT-CACHE-NO.  This effectively disables method.~%~
  1275. X       lookup caching.  See the definition of object-cache-no in the file~%~
  1276. X       low to get an idea of how to implement object-cache-no."))
  1277. X  `(logand 0 ,mask))
  1278. X
  1279. X
  1280. X  ;;   
  1281. X;;;;;; FUNCTION-ARGLIST
  1282. X  ;;
  1283. X;;; Given something which is functionp, function-arglist should return the
  1284. X;;; argument list for it.  PCL does not count on having this available, but
  1285. X;;; MAKE-SPECIALIZABLE works much better if it is available.  Versions of
  1286. X;;; function-arglist for each specific port of pcl should be put in the
  1287. X;;; appropriate xxx-low file. This is what it should look like:
  1288. X;(defun function-arglist (function)
  1289. X;  (<system-dependent-arglist-function> function))
  1290. X
  1291. X(defun function-pretty-arglist (function)
  1292. X  (ignore function)
  1293. X  ())
  1294. X
  1295. X(defsetf function-pretty-arglist set-function-pretty-arglist)
  1296. X
  1297. X(defun set-function-pretty-arglist (function new-value)
  1298. X  (ignore function)
  1299. X  new-value)
  1300. X
  1301. X
  1302. X
  1303. X  ;;   
  1304. X;;;;;; Templated functions
  1305. X  ;;   
  1306. X;;; In CommonLoops there are many program-generated functions which
  1307. X;;; differ from other, similar program-generated functions only in the
  1308. X;;; values of certain in-line constants.
  1309. X;;;
  1310. X;;; A prototypical example is the family of discriminating functions used by
  1311. X;;; classical discriminators.  For all classical discriminators which have
  1312. X;;; the same number of required arguments and no &rest argument, the
  1313. X;;; discriminating function is the same, except for the value of the
  1314. X;;; "in-line" constants (the cache and discriminator).
  1315. X;;;
  1316. X;;; Naively, whenever we want one of these functions we have to produce and
  1317. X;;; compile separate lambda. But this is very expensive, instead what we
  1318. X;;; would like to do is copy the existing compiled code and replace the
  1319. X;;; values of the inline constants with the right new values.
  1320. X;;;
  1321. X;;; Templated functions provide a nice interface to this abstraction of
  1322. X;;; copying an existing compiled function and replacing certain constants
  1323. X;;; with others.  Templated functions are based on the assumption that for
  1324. X;;; any given CommonLisp one of the following is true:
  1325. X;;;   Either:
  1326. X;;;     Funcalling a lexical closure is fast, and lexical variable access
  1327. X;;;     is as fast (or about as fast) in-line constant access.  In this
  1328. X;;;     case we implement templated functions as lexical closures closed
  1329. X;;;     over the constants we want to change from one instance of the
  1330. X;;;     templated function to another.
  1331. X;;;   Or:
  1332. X;;;     Code can be written to take a compiled code object, copy it and
  1333. X;;;     replace references to certain in-line constants with references
  1334. X;;;     to other in-line constants.
  1335. X;;;
  1336. X;;; Actually, I believe that for most Lisp both of the above assumptions are
  1337. X;;; true.  For certain lisps the explicit copy and replace scheme *may be*
  1338. X;;; more efficient but the lexical closure scheme is completely portable and
  1339. X;;; is likely to be more efficient since the lexical closure it returns are
  1340. X;;; likely to share compiled code objects and only have separate lexical
  1341. X;;; environments.
  1342. X;;;
  1343. X;;; Another thing to notice about templated functions is that they provide
  1344. X;;; the modularity to support special objects which a particular
  1345. X;;; implementation's low-level function-calling code might know about.   As
  1346. X;;; an example, when a classical discriminating function is created, the
  1347. X;;; code says "make a classical discriminating function with 1 required
  1348. X;;; arguments". It then uses whatever comes back from the templated function
  1349. X;;; code as the the discriminating function So, a particular port can easily
  1350. X;;; make this return any sort of special data structure instead of one of
  1351. X;;; the lexical closures the portable implementation returns.
  1352. X;;;
  1353. X(defvar *templated-function-types* ())
  1354. X(defmacro define-function-template (name
  1355. X                    template-parameters
  1356. X                    instance-parameters
  1357. X                    &body body)
  1358. X  `(progn
  1359. X     (pushnew ',name *templated-function-types*)
  1360. X     ;; Get rid of all the cached constructors.
  1361. X     (setf (get ',name 'templated-fn-constructors) ())
  1362. X     ;; Now define the constructor constructor.
  1363. X     (setf (get ',name 'templated-fn-params)
  1364. X       (list* ',template-parameters ',instance-parameters ',body))
  1365. X     (setf (get ',name 'templated-fn-constructor-constructor)
  1366. X       ,(make-templated-function-constructor-constructor
  1367. X          template-parameters instance-parameters body))))
  1368. X
  1369. X(defun reset-templated-function-types ()
  1370. X  (dolist (type *templated-function-types*)
  1371. X    (setf (get type 'templated-fn-constructors) ())))
  1372. X
  1373. X(defun get-templated-function-constructor (name &rest template-parameters)
  1374. X  (setq template-parameters (copy-list template-parameters)) ;Groan.
  1375. X  (let ((existing (assoc template-parameters
  1376. X             (get name 'templated-fn-constructors)
  1377. X             :test #'equal)))
  1378. X    (if existing
  1379. X    (progn (setf (nth 3 existing) t)    ;Mark this constructor as
  1380. X                        ;having been used.
  1381. X           (cadr existing))            ;And return the actual
  1382. X                        ;constructor.
  1383. X    (let ((new-constructor
  1384. X        (apply (get name 'templated-fn-constructor-constructor)
  1385. X               template-parameters)))
  1386. X      (push (list template-parameters new-constructor 'made-on-the-fly t)
  1387. X        (get name 'templated-fn-constructors))
  1388. X      new-constructor))))
  1389. X
  1390. X(defmacro pre-make-templated-function-constructor (name
  1391. X                           &rest template-parameters)
  1392. X  (setq template-parameters (copy-list template-parameters))    ;Groan.
  1393. X  (let* ((params (get name 'templated-fn-params))
  1394. X     (template-params (car params))
  1395. X     (instance-params (cadr params))
  1396. X     (body (cddr params))
  1397. X     (dummy-fn-name (gensym)))   ;For the 3600, which doesn't bother to 
  1398. X                     ;compile top-level forms, we do the
  1399. X                     ;top-level form compilation by hand.
  1400. X    (progv template-params
  1401. X       template-parameters
  1402. X      `(progn
  1403. X     (defun ,dummy-fn-name ()
  1404. X       (let ((entry
  1405. X           (or (assoc ',template-parameters 
  1406. X                  (get ',name 'templated-fn-constructors)
  1407. X                  :test #'equal)
  1408. X               (let ((new-entry
  1409. X                   (list ',template-parameters () () ())))
  1410. X             (push new-entry
  1411. X                   (get ',name 'templated-fn-constructors))
  1412. X             new-entry))))
  1413. X         (setf (caddr entry) 'pre-made)
  1414. X         (setf (cadr entry)
  1415. X           (function (lambda ,(eval instance-params)
  1416. X                   ,(eval (cons 'progn body)))))))
  1417. X     (,dummy-fn-name)))))
  1418. X
  1419. X(defun make-templated-function-constructor-constructor (template-params
  1420. X                            instance-params
  1421. X                            body)
  1422. X  `(function
  1423. X     (lambda ,template-params
  1424. X       (compile () (list 'lambda ,instance-params ,@body)))))
  1425. X
  1426. X  ;;   
  1427. X;;;;;; 
  1428. X  ;;   
  1429. X
  1430. X(defun record-definition (name type &rest args)
  1431. X  (ignore name type args)
  1432. X  ())
  1433. X
  1434. X(defun compile-time-define (&rest ignore)
  1435. X  (ignore ignore))
  1436. X
  1437. END_OF_FILE
  1438. if test 27849 -ne `wc -c <'low.l'`; then
  1439.     echo shar: \"'low.l'\" unpacked with wrong size!
  1440. fi
  1441. # end of 'low.l'
  1442. fi
  1443. echo shar: End of archive 8 \(of 13\).
  1444. cp /dev/null ark8isdone
  1445. MISSING=""
  1446. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 ; do
  1447.     if test ! -f ark${I}isdone ; then
  1448.     MISSING="${MISSING} ${I}"
  1449.     fi
  1450. done
  1451. if test "${MISSING}" = "" ; then
  1452.     echo You have unpacked all 13 archives.
  1453.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1454. else
  1455.     echo You still need to unpack the following archives:
  1456.     echo "        " ${MISSING}
  1457. fi
  1458. ##  End of shell archive.
  1459. exit 0
  1460. -- 
  1461.  
  1462. Rich $alz            "Anger is an energy"
  1463. Cronus Project, BBN Labs    rsalz@bbn.com
  1464. Moderator, comp.sources.unix    sources@uunet.uu.net
  1465.